#pragma once
#include <iostream>
#include "mysocket.hpp"
#include <poll.h>
#include <vector>

using namespace std;

class PollServer
{
    static const int DEF_FD = -1;
    static const int INIT_SZ = 2;   //_pollfds的初始容量，可以设置为1024
    static const int NON_EVENT = 0; // 用于清空event
    Socket _listensock;
    uint16_t _port;
    string _ip;
    vector<pollfd> _pollfds; // 使用vector数组，动态分配内存
    int _real_nfds;          // 记录数组中实际建立连接的描述符数量

public:
    PollServer(uint16_t port, const string ip = "0.0.0.0")
        : _port(port),
          _ip(ip),
          _pollfds(INIT_SZ, {DEF_FD, NON_EVENT, NON_EVENT}) // 注意初始化
    {
        _pollfds[0].fd = _listensock.getsock();
        _pollfds[0].events = POLLIN;
        _real_nfds = 1;
    }

    void Init()
    {
        _listensock.Bind(_ip, _port);
        _listensock.Listen();
    }

    void Run()
    {
        while (true)
        {
            int n = poll(_pollfds.data(), _pollfds.size(), 5000); // vector::data() 返回数组首地址，可以像原生数组一样使用了！
            if (n == 0)                                           // 没有文件描述符就绪
            {
                cout << "timeout!" << endl;
                // do other thing...
            }
            else if (n > 0) // 有n个文件描述符就绪
            {
                cout << n << " fd ready!" << endl;
                Dispatcher(); // 将就绪的套接字分派给连接管理器或通信服务器
            }
            else // 发生错误
            {
                cout << "select error!" << endl;
            }
            cout << "----------------------------------" << endl;
        }
    }

    ~PollServer()
    {
        for (int i = 0; i < _pollfds.size(); ++i)
        {
            if (_pollfds[i].fd != DEF_FD)
            {
                close(_pollfds[i].fd);
            }
        }
    }

private:
    void Dispatcher()
    {
        if (_pollfds[0].revents & POLLIN) // 监听套接字就绪，可以直接accept获取新链接
        {
            Acceptor();
        }
        for (int i = 1; i < _pollfds.size(); ++i) // 其他套接字就绪，可以直接recv读取并处理数据
        {
            if (_pollfds[i].fd != DEF_FD && _pollfds[i].revents & POLLIN)
            {
                Receiver(_pollfds[i].fd, i);
            }
        }
    }

    void Acceptor()
    {
        string ip;
        uint16_t port;
        int svcfd = _listensock.Accept(&ip, &port);
        if (svcfd == -1)
            return;
        cout << "get a new link! " << ip << "/" << port << endl;
        if (_real_nfds == _pollfds.size())
        {
            _pollfds.resize(_pollfds.size() * 2, {DEF_FD, NON_EVENT, NON_EVENT});
            cout << "pollfds is full! resize now, newsize: " << _pollfds.size() << endl;
        }
        for (int i = 0; i < _pollfds.size(); ++i)
        {
            if (_pollfds[i].fd == DEF_FD)
            {
                _pollfds[i].fd = svcfd;
                _pollfds[i].events = POLLIN;
                _pollfds[i].revents = NON_EVENT; // 注意一定要清零！
                ++_real_nfds;
                cout << ip << "/" << port << " --> " << svcfd << endl;
                break;
            }
        }
    }

    void Receiver(int fd, int pos)
    {
        char buffer[1024];
        int sz = recv(fd, &buffer, sizeof(buffer) - 1, 0);
        if (sz > 0)
        {
            buffer[sz] = 0;
            cout << "get a message from fd" << fd << endl
                 << "echo: " << buffer;
        }
        else if (sz == 0)
        {
            close(fd);
            _pollfds[pos].fd = DEF_FD;
            --_real_nfds;
            cout << "client quit, service end. close fd" << fd << endl;
        }
        else
        {
            perror("recv");
            exit(errno);
        }
    }
};